package com.wang.project.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.wang.project.common.ErrorCode;
import com.wang.project.exception.BusinessException;
import com.wang.project.model.entity.User;
import com.wang.project.model.file.*;
import com.wang.project.service.FileService;
import com.wang.project.service.UserService;
import com.wang.project.utils.FileUtils;
import com.wang.project.utils.MinioUtil;
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import io.minio.errors.*;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.OutputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Random;

@Service
@Slf4j
public class FileServiceImpl implements FileService {
    @Resource
    private MinioUtil minioUtil;

    @Autowired
    private MinioClient minioClient;

    @Resource
    private UserService userService;

    private final Long maxSize = (long) (1024 * 1024);

    //存储桶名称
    @Value("${minio.bucketName}")
    private String bucketName;


    /**
     * 文件上传
     *
     * @param file
     * @param param
     * @return
     * @throws Exception
     */
    @Override
    public Boolean uploadFile(MultipartFile file, FileUploadParam param, User user) throws Exception {
        log.info("FileServiceImpl uploadFile FileUploadParam:{}", JSONUtil.toJsonStr(param));
        //判断文件是否为空
        if (null == file || 0 == file.getSize()) {
            return null;
        }
        log.info("bucketName:{}", bucketName);
        //判断存储桶是否存在  不存在则创建
        minioUtil.createBucket(bucketName);
        //原始文件名
        String originalFilename = file.getOriginalFilename();
        //新的文件名 = 操作类型+操作作用+用户账号
        assert originalFilename != null;
        String fileName = FileUtils.getMinioUploadFileName(param, user) + originalFilename.substring(originalFilename.lastIndexOf("."));
        log.info("FileServiceImpl uploadFile fileName:{}", fileName);
        //开始上传
//        log.info("file压缩前大小:{}", file.getSize());
        /*if (file.getSize() > maxSize) {
            FileItemFactory fileItemFactory = new DiskFileItemFactory();
            FileItem fileItem = fileItemFactory.createItem(fileName, "text/plain", true, fileName);
            OutputStream outputStream = fileItem.getOutputStream();
            Thumbnails.of(file.getInputStream()).scale(1f).outputFormat(originalFilename.substring(originalFilename.lastIndexOf(".") + 1)).outputQuality(0.25f).toOutputStream(outputStream);
            file = new CommonsMultipartFile(fileItem);
        }*/
//        log.info("file压缩后大小:{}", file.getSize());
        minioClient.putObject(
                PutObjectArgs.builder().bucket(bucketName).object(fileName).stream(
                                file.getInputStream(), file.getSize(), -1)
                        .contentType(file.getContentType())
                        .build());
        log.info("MinioUtil uploadFile success");
        return Boolean.TRUE;
    }

    /**
     * 通用获取文件地址
     *
     * @param param
     * @param user
     * @return
     */
    @Override
    public String getObjectURL(FileQueryUrlParam param, User user) {
        final Integer expires = 5;
        String originalFilename = param.getOriginalFilename();
        FileUploadParam fileUploadParam = new FileUploadParam();
        fileUploadParam.setType(param.getType());
        fileUploadParam.setRegion(param.getRegion());
        log.info("FileServiceImpl getObjectURL originalFilename:{},fileUploadPara:{}", originalFilename, fileUploadParam);
        String fileName = FileUtils.getMinioUploadFileName(fileUploadParam, user) + originalFilename.substring(originalFilename.lastIndexOf("."));
        log.info("FileServiceImpl getObjectURL fileName:{}", fileName);
        try {
            return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(bucketName).object(fileName).build());
        } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException |
                 InvalidResponseException | IOException | NoSuchAlgorithmException | XmlParserException |
                 ServerException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取用户头像地址
     *
     * @param param
     * @param user
     * @return
     */
    @Override
    public String getUserAvatarUrl(FileQueryUrlParam param, User user) {
        String userAvatarUrl = user.getUserAvatar();
        //获取文件在线地址中的文件名
        String originalFilename = FileUtils.getFileNameByUrl(userAvatarUrl);
        if (originalFilename == null) {
            log.info("FileServiceImpl getUserAvatarUrl originalFilename is null");
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "用户头像地址错误，请检查");
        }
        FileUploadParam fileUploadParam = new FileUploadParam();
        fileUploadParam.setType(param.getType());
        fileUploadParam.setRegion(param.getRegion());
        log.info("FileServiceImpl getObjectURL originalFilename:{},fileUploadPara:{}", originalFilename, fileUploadParam);
        String fileName = FileUtils.getMinioUploadFileName(fileUploadParam, user) + originalFilename.substring(originalFilename.lastIndexOf("."));
        try {
            return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(bucketName).object(fileName).build());
        } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException |
                 InvalidResponseException | IOException | NoSuchAlgorithmException | XmlParserException |
                 ServerException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 删除用户头像文件
     *
     * @param fileName
     */
    @Override
    public void removeUserAvatar(String fileName) {
        try {
            minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());
        } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException |
                 InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException |
                 XmlParserException e) {
            throw new RuntimeException(e);
        }
    }
}
